(function(){

    //http://blog.jcoglan.com/2007/10/30/asynchronous-function-chaining-in-javascript/   thanks!!!!!!
    var ChainCollector = function(base) {
    var CLASS = arguments.callee;

    this.then = this.and = this;
    var queue = [], baseObject = base || {};

    this.____ = function(method, args) {
        queue.push({func: method, args: args});
    };

    this.fire = function(base) {
        var object = base || baseObject, method, property;
        for (var i = 0, n = queue.length; i < n; i++) {
            method = queue[i];
            if (object instanceof CLASS) {
                object.____(method.func, method.args);
                continue;
            }
            property = object[method.func];
            object = (typeof property == 'function')
                    ? property.apply(object, method.args)
                    : property;
        }
        return object;
    };
};

ChainCollector.addMethods = function(object) {
    var methods = [], property, i, n, name;
    var self = this.prototype;

    var reservedNames = [], blank = new this();
    for (property in blank) reservedNames.push(property);
    var re = new RegExp('^(?:' + reservedNames.join('|') + ')$');

    for (property in object) {
        if (Number(property) != property)
            methods.push(property);
    }
    if (object instanceof Array) {
        for (i = 0, n = object.length; i < n; i++) {
            if (typeof object[i] == 'string')
                methods.push(object[i]);
        }
    }
    for (i = 0, n = methods.length ; i < n; i++)
        (function(name) {
            if (re.test(name)) return;
            self[name] = function() {
                this.____(name, arguments);
                return this;
            };
        })(methods[i]);

    if (object.prototype)
        this.addMethods(object.prototype);
};



//FROM JQUERY
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/;













var undefined,
  // _booky, //self
    booky = window.booky = function(selector, context, findSelector) { 
        return new booky.fn.init(selector, context, findSelector);  
    };



booky.fn = booky.prototype = { //jqueyr doent seem quite right, or can i still get teh booky.woo rather than 
    version: "0.01a",
    debug: false,
    
    init: function(selector, context, findSelector) { 
        

      //  _booky = this;//this will conflict with other ones..perhaps use arguments.callee in each()?
        this.length = 0;    
      //  this.loaded = false;
        this.onload = null;   
        
        //clean up just incase it is reiniting as part of a chain  e.g property("color","red").init()
        this.clear();    
        
        //for pushStack, handle the previous findSelector()   
        if(typeof findSelector !== "undefined") {
            this.findSelector = findSelector; //it is creating a new object from the search
        }

        //handle context
        if(typeof context !== "undefined") {
            if(typeof context === "string") {
                context = this.sel(context);
            }          
        }
        
            
        //Handle no selector
        if (typeof selector === "undefined") { 
            //?????????
            return this;
        }

        //Add a rule or search for rules
        else if ( typeof selector === "string" ) { 
            
			// Are we dealing with HTML string or an ID?
			var match = quickExpr.exec( selector );

			// Verify a match, and that no context was specified for #id
			if ( match && (match[1] || !context) ) {			
                //if html  
                this.initDocFrag(booky.fn.getFrag(selector)); 
                return this;
                                 
            }
            else {            
			    //selector
                var els = this.sel(selector);
                this.length = els.length;
                for(var i=0;i<this.length;i++) 
                    this[i] = els[i];    
                
            }
            
        }
        
        
        //HTML Element
        else if ( selector.nodeType ) { 
            if(selector.nodeType === 11) { //document frag
                this.log("Init:\Doc frag");
                this.initDocFrag(selector);
                
            } 
            else  {
                this.log("Init:\tHTML elem");
                this[0] = selector;
                this.length = 1;
                
            }
            //return this.getComputedStyle(selector); //or getAffectingRules???             
        }
        
        
        
        //Object, Rules list or random    
        else if ( typeof selector === "object" ) {     
               
            if(selector.length) {
                for(var i=0;i<selector.length;i++) {
                   this[i] = selector[i];
                }   
                this.length = selector.length;
                return  this;
            }                
                    
            else {
                this.log("Init:\tunkown:s this?", selector);
            }
        }       
        
        
        return this;          
        
    },
    
    initDocFrag: function(frag) {
        this.clear();
        this.length = frag.childNodes.length;             
        for(var i=0;i<frag.childNodes.length;i++)  
            this[i] = frag.childNodes[i];  
                        
        return this;    
    },
          
    getFrag: function(s) {
        if(typeof s === "undefined")
            this.log("getFrag: no html string");
        var frag = document.createDocumentFragment(),
            wrap = document.createElement("DIV");
            
        wrap.innerHTML = s;
        
        while(wrap.childNodes.length>0) 
            frag.appendChild(wrap.childNodes[0]);    

        return frag;
    },

    //convert current selction to frag
    makeFrag: function() {
        var frag = document.createDocumentFragment();          
        for(var i=0;i<this.length;i++)  
            frag.appendChild(this[i]);
        this.clear();
        this[0] = frag;;        
        this.length = 1;
            return this;
    },
              
   
    clear: function() {
        if(this.length>0) {
            this.eq(0);
            delete this[0];
        }
        this.length = 0;
        return this;
    }, 
    
    //from jQuery
	eq: function( i ) {
		return this.slice( i, i + 1 );
	},
    //from jQuery
	slice: function() {
		return this.pushStack( Array.prototype.slice.apply( this, arguments ) );
	},
	
	// Take an array of elements and push it onto the stack
	// (returning the new matched element set)
	pushStack: function( elems ) {
		// Build a new jQuery matched element set
		var ret = booky( elems );

		// Add the old object onto the stack (as a reference)
		ret.prevObject = this;

		// Return the newly-formed element set
		return ret;
	},    
	
	
	
    //appendHtml: function (html)
    load: function(settings/*,checkIfLoaded, html, toLoad*/) {//overlay: true, multipleInstances:true, loadingHtml: loadingHtml, libs:
        //check if its loaded already
        if(settings.multipleInstances /*&& booky.loaded*/) {
            alert("loaded already");
            return false;
        }
        //_booky.loaded = true;
        this.onload = settings.onload;
        
        //add loading window
        var loadingDiv = document.createElement("DIV");        //need a jquery append html type thing...perhaps leave ot jquery, or just get the very mostly used bits
        loadingDiv.innerHTML = typeof settings.loadingHtml != "undefined" ? settings.loadingHtml:
        "<div class='bookyTitleBar' style='    color:#fff;    background:#a5c9ef url(windowbarbg.gif) top left no-repeat;    height:18px;    line-height:18px;    padding-left:2px;font-weight:bold;'>"+
        "<span class='bookyTitle' style=' float:left;cursor:default;'>Loading...</span></div><div id='bookyCurrent' style='padding:2px;'></div>";
        this[0] = loadingDiv;
        
        this.styles({        
           // border:"1px solid blue",position:"fixed", margin:"0 auto", width:"200px", height:"80px", fontFamily:"Tahoma, Arial",  zIndex:"10000"},
            width:"200px",
            //height:"80px",
            background: "#D4D0C8",
            fontFamily:"Tahoma, Arial",
            fontSize:"11px",
            border:"1px outset #666666",
            position:"absolute",
            overflow:"hidden",
            zIndex:"9999"}            
        );
        loadingDiv.id = "bookyLoading";
        
        
        document.body.appendChild(loadingDiv);
        this.center(loadingDiv);
        if(settings.overlay) {
            this.overlay(true);
        }
        
        
        //load stuff
        this.loadScripts(settings.libs, this.onload); //skip css for now
       
        
        return this;                      
    },
    
    
    
    overlay: function(on) { //put the overlay code in this, allow it to turn on off etc..
        if(!on) {
            booky(this.overlayEl).rem();
            return;
        }
        document.body.style.margin="0";
        this.overlayEl = document.createElement("DIV");        //need a jquery append html type thing...perhaps leave ot jquery, or just get the very mostly used bits
        this.styles(this.overlayEl, {background:"#000",opacity:"0.3",filter:"alpha(opacity=30);", position:"fixed",top:"0", left:"0", width:"100%", height:"100%", zIndex:"9998"});
        this.overlayEl.id = "bookyOverlay";
        document.body.appendChild(this.overlayEl);
        return this;
    },
    
    
    center: function(el) {
        el.style.left = (this.getViewPortDimensions().width -el.clientWidth) / 2 +"px"// - el.style.height;
        el.style.top = (this.getViewPortDimensions().height-el.clientHeight) / 2 +"px";
        return this;
    },  
    

    //thanks http://www.howtocreate.co.uk/tutorials/javascript/browserwindow
    getViewPortDimensions: function () {

        var myWidth = 0, myHeight = 0;
        
        if( typeof( window.innerWidth ) == 'number' ) {
            //Non-IE
            myWidth = window.innerWidth;
            myHeight = window.innerHeight;
            
        } else if( document.documentElement && ( document.documentElement.clientWidth || document.documentElement.clientHeight ) ) {
            //IE 6+ in 'standards compliant mode'
            myWidth = document.documentElement.clientWidth;
            myHeight = document.documentElement.clientHeight;
            
        } else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
            //IE 4 compatible
            myWidth = document.body.clientWidth;
            myHeight = document.body.clientHeight;
        }
        
        return {width: myWidth, height: myHeight};
    },
          
    
    
    
    //setting css without a stylesheet
    styles: function(styles) {
        for(style in styles)         
            this[0].style[style] = styles[style];
        return this;
    }, 
    
    //MUST DO EACH LOOP ON THESE.!!
    addClass: function(c) {      //shoudl fix up jquery style so i can do booky(win).addClass etc....   
        return this.each(function() {
            if(!booky(this).hasClass(c)) this.className += (" " + c); 
        }); 
        
    }, 
    hasClass: function(c) {      //shoudl fix up jquery style so i can do booky(win).addClass etc....           
        return RegExp("\\b"+c+"\\b").test(this[0].className);  
    }, 
    removeClass: function(c) {      //shoudl fix up jquery style so i can do booky(win).addClass etc....    
        return this.each(function() {
            this.className = this.className.replace(RegExp("\\b"+c+"\\b", "g"), "");
        });         
    },               

    loadCSS: function(url, todo) {    
        var cssNode;
        if(document.createStyleSheet) {      
            document.createStyleSheet(url); //add sheet by URL 
            cssNode = document.styleSheets[document.styleSheets.length-1]
        }
        else {          
            head = document.getElementsByTagName("head")[0]      
            cssNode = document.createElement('link');
            cssNode.type = 'text/css';
            cssNode.rel =  'stylesheet';
            cssNode.href =  url;
            cssNode.media= 'screen';      
            head.appendChild(cssNode);  
        }    

        //need to check later to see if it is loaded
        var testCss = setInterval(function() {
            try {
                if(cssNode.sheet) cssNode = cssNode.sheet//does not load appear immediately in webkit, so must set it each time (same for catch block..)
                
                if(cssNode.cssText || (cssNode.cssRules && cssNode.cssRules.length > 0)) {
                    clearInterval(testCss);
                    booky("#bookyCurrent")[0].html += "loaded " + url;         //should be custom..... so can use at any time
                    todo();
            }    
            }catch(e){}
        
        } , 20);
            
       return this;
    },
    
    //load async to be faster...
    loadScripts: function(arrScripts, todo) {
        var scriptsToLoadCount = arrScripts.length,
            scriptLoadCount = 0;     
             
        for(var i = 0; i<scriptsToLoadCount;i++) {
            if(arrScripts[0].search(/\.css$/) > 0) 
                this.loadCSS(arrScripts.shift() , loadedFile);
            else 
                this.loadScript(arrScripts.shift(), loadedFile);  
        }

        function loadedFile() {
            scriptLoadCount++;
            if(  scriptLoadCount ==  scriptsToLoadCount ) {     
                booky("#bookyLoading, #bookyOverlay").rem();
                
  
                if(typeof todo === "function") todo();
            }                    
        }                
    },
            
    
    loadScript:  function(url, todo) {
        var div = document.createElement("div");
        div.innerHTML = url;
        this.sel("#bookyCurrent")[0].appendChild(div);
        var script = document.createElement('script');
            script.setAttribute('src', url);
            script.onload = script.onreadystatechange = function() {  
                if(typeof this.readyState !== "undefined")
                    if(this.readyState !== "complete" && this.readyState !== "loaded")
                        return;
                        
                div.innerHTML += " loaded!";
                div.style.color = "green";  
                if(typeof todo === "function") todo();
            };//need todo for css...
        document.getElementsByTagName("head")[0].appendChild(script);
    },
          
          
          
          
          
          
    //mini helpers   
    
    
    
    //from jQuery     
    trim: function( text ) {
        return (text || "").replace( /^\s+|\s+$/g, "" );
    },

    //updates:  "div.class, span.class2" - split and wrap around whole lot
    //fix to use each: !!!
    sel: function(s, context) {
        s = this.trim(s);
        var   currentSelector,
              bits = s.split(" "),
              els = [],
              //it needs to have some context, and that context to be an array
              context = typeof context === "undefined" ? [document] : context,
              context = typeof context.length === "undefined" ? [context] : context;
              

        //if comma seperated list  
        if(s.split(",").length > 1) {
            bits = s.split(",");
            for(bit in bits) {
                this.sel(this.trim(bits[bit]), context)                     
                els = els.concat(this.sel(this.trim(bits[bit]), context));
            }    
            return els;
        }     
        while(bits.length>0) {
            currentSelector = bits.shift();       
            els = [];                
            for(var i=0; i<context.length; i++) {  
                if(currentSelector.charAt(0) == "#") {
                    els = document.getElementById(currentSelector.substr(1)) == null ? [] : [document.getElementById(currentSelector.substr(1))];                            
                    break;
                }
                else if(currentSelector.charAt(0) == ".") {
                    els = concat(els, getElementsByClassName(currentSelector.substr(1), context[i]));
                }
                else {
                    els = concat(els, context[i].getElementsByTagName(currentSelector.toUpperCase()));   
                }
            }    
            context = els;
        }             
           
        return els;
        
        
        
        function getElementsByClassName(c, contextEl) {
            if(contextEl.getElementsByClassName)
                return contextEl.getElementsByClassName(c);
        
            var all = contextEl.getElementsByTagName("*"),  len = all.length, els = [];
            for(var i=0;i<len;i++) {
                if(RegExp("\\b"+c+"\\b", "i").test(all[i].className)) 
                    els.push(all[i]);
            }
            return els;
        }
        
        //concat array-like objects
        function concat(a,a2) {
            for(var i=0;i<a2.length;i++) 
                a.push(a2[i]);                    
            return a;
        }                
    },
    
    //from jQuery
    each: function( object, callback, args ) {
        if(typeof object === "function") {callback = object; object = this; }		
        var name, i = 0, length = object.length;

        if ( args ) {
            if ( length == undefined ) {
                for ( name in object )
                    if ( callback.apply( object[ name ], args ) === false )
                        break;
            } else
                for ( ; i < length; )
                    if ( callback.apply( object[ i++ ], args ) === false )
                        break;

        // A special, fast, case for the most common use of each
        } else {
            if ( length == undefined ) {
                for ( name in object )
                    if ( callback.call( object[ name ], name, object[ name ] ) === false )
                        break;
            } else
                for ( var value = object[0];
                    i < length && callback.call( value, i, value ) !== false; value = object[++i] ){}
        }


        return object;
    },

    appendTo: function(el) {
        var el = booky(el)[0];
        return this.each(function() {
        console.log(this , " appends to ",el)
            //el.appendChild(this);
        });    
    },        
    
    
    //screws it up sometimes...
    find: function(selector, context) {
        context = typeof context === "undefined" ? this : context;
        return booky().sel(selector, context); 
    },
    
    
    
    
    
    
    
    
    
    rem: function () {    
      
        /*this.each(function() {      
            if(this.parentNode)          
                this.parentNode.removeChild(this);
        });
        BUST*/
        for(var i=0;i<this.length;i++)
            if(this[i].parentNode)          
                this[i].parentNode.removeChild(this[i]);
        
        this.clear();
        return this;
    },
    
    log: function(m, m2) { 
        if(!this.debug) return this;
        try {
            console.log(this, m, m2);                
        } catch(e){}
        
        return this;
    },
    
    //run a function then return itself.!!!     use in the animations too!!,should allow callbacks also
    run: function(f) {
        f();
        return this;
    },
    wait: function(time) {
        var collector = new ChainCollector(), self = this;
        // Deal with scoping issues...
        var fire = function() { collector.fire(self); };
        setTimeout(fire, Number(time) * 1000);
        return collector;    
    },
    
    
    
        
        
        
    //merges array2 _into_ defaults
    merge: function(defaults, array2) {    
        if(defaults && array2)    
            for(def in defaults)    
                for(merg in array2) 
                    defaults[merg] = array2[merg];            
    },

    
    
};




//ty jQuery !!
booky.prototype.init.prototype = booky.prototype;
//async
ChainCollector.addMethods(booky);
 
 

 
 
 
//init itself
booky().load( {libs: ["booky.app.js"]} );
        
 
 
 
 
})();